import math

import numpy as np
import math as m


class ELECTRE:
    def __init__(self, DecisionMatrix, weight, q):
        '''
        假设只有效益型
        :param DecisionMatrix: 决策矩阵
        :param wight: 属性权重
        :param q: q值
        '''
        self.matrix = DecisionMatrix
        self.weight = weight
        self.q = q

    def addition(self, Ivq1, Ivq2, q):
        '''
        加法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a ** q + e ** q - (a ** q) * (e ** q)
        u2 = b ** q + f ** q - (b ** q) * (f ** q)
        v1 = c * g
        v2 = h * d
        return ([u1, u2], [v1, v2])

    def subtraction(self, Ivq1, Ivq2, q):
        '''
        减法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a * g
        u2 = b * h
        v1 = (c ** q + e ** q - (c ** q) * (e ** q)) ** (1 / q)
        v2 = (d ** q + f ** q - (d ** q) * (f ** q)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    def multiplication(self, Ivq1, Ivq2, q):
        '''
        乘法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a * e
        u2 = b * f
        v1 = (c ** q + g ** q - (c ** q) * (g ** q)) ** (1 / q)
        v2 = (d ** q + h ** q - (d ** q) * (h ** q)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    def division(self, Ivq1, Ivq2, q):
        '''
        除法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = (a ** q + g ** q - (a ** q) * (g ** q)) ** (1 / q)
        u2 = (b ** q + h ** q - (b ** q) * (h ** q)) ** (1 / q)
        v1 = c * e
        v2 = d * f
        return ([u1, u2], [v1, v2])

    def getscore(self, IVq):
        '''
        我们提出的得分函数
        :param IVq:区间值
        :param q:q值
        :return:
        '''
        a = IVq[0][0]
        b = IVq[0][1]
        c = IVq[1][0]
        d = IVq[1][1]
        score=(m.log(a + b + c + d + 1) + (b - a) + (d - c) ** 2 +(a - c + b - d) * m.log(3) / 2) / (2 * m.log(3))
        if score==0:
            return (a+b+c+d)*0.2
        else:
            return (m.log(a + b + c + d + 1) + (b - a) + (d - c) ** 2 +(a - c + b - d) * m.log(3) / 2) / (2 * m.log(3))
        # return (a+b+c+d)*0.5+1

    def Exponentiation(self, Ivq1, q, n):
        '''
        次方运算
        :param Ivq1:
        :param q:
        :param n:开多少次方
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        u1 = a ** n
        u2 = b ** n
        v1 = (1 - ((1 - (c ** q)) ** n)) ** (1 / q)
        v2 = (1 - ((1 - (d ** q)) ** n)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    def getPosNegPoint(self, NormalizedMatrix):
        '''
        求正负理想解
        :param NormalizedMatrix: 区间值矩阵
        :param q: q值
        :return: 传入区间值矩阵的贴近度矩阵
        '''
        Row, Column = len(NormalizedMatrix), len(NormalizedMatrix[0])
        Positiveline, Negativeline = [], []
        for i in range(Row):
            Positiveidu1 = []
            Positiveidu2 = []
            Positiveidu3 = []
            Positiveidu4 = []

            for j in range(Column):
                ##求理想点
                Positive1 = NormalizedMatrix[i][j][0][0]
                Positive2 = NormalizedMatrix[i][j][0][1]
                Positive3 = NormalizedMatrix[i][j][1][0]
                Positive4 = NormalizedMatrix[i][j][1][0]

                Positiveidu1.append(Positive1)
                Positiveidu2.append(Positive2)
                Positiveidu3.append(Positive3)
                Positiveidu4.append(Positive4)

            A_max1 = np.max(Positiveidu1)
            A_max2 = np.max(Positiveidu2)
            A_max3 = np.min(Positiveidu3)
            A_max4 = np.min(Positiveidu4)

            A_min1 = np.min(Positiveidu1)
            A_min2 = np.min(Positiveidu2)
            A_min3 = np.max(Positiveidu3)
            A_min4 = np.max(Positiveidu4)

            Positiveline.append(([A_max1, A_max2], [A_max3, A_max4]))
            Negativeline.append(([A_min1, A_min2], [A_min3, A_min4]))
        return Positiveline, Negativeline

    def Normalized(self, Matrix, Weight):
        '''
        规范化
        :param Matrix: 区间矩阵
        :param Weight: 权重
        :return:
        '''
        rij = []
        for i in range(5):
            rnext = []
            for j in range(5):
                up = Matrix[i][j]
                for j0 in range(5):
                    x = self.Exponentiation(Matrix[i][j0], self.q, 2)
                    if (j0 == 0):
                        down = x
                    else:
                        down = self.addition(down, x, self.q)
                down = self.Exponentiation(down, self.q, 0.5)
                div = self.division(up, down, self.q)
                div = ([div[0][0] * weight[i], div[0][1] * weight[i]], [div[1][0] * weight[i], div[1][1] * weight[i]])
                rnext.append(div)
            rij.append(rnext)
        return rij

    def getPosNor(self, Ivq, Pos, Neg, q):
        '''
        对正类型的指标进行处理
        :param Ivq: 区间值
        :param Pos: 正理想解元素
        :param Neg: 负理想解元素
        :param q: q值
        :return:
        '''
        PosNor = self.division(self.subtraction(Ivq, Neg, q), self.subtraction(Pos, Neg, q), q)
        return PosNor

    def DominantMatrix(self, NormalizedMatrix, Weight):
        '''
        占优矩阵
        :param NormalizedMatrix: 区间值矩阵
        :param Weight: 权重
        :return:
        '''
        Gik = []
        sum = [0, 0, 0, 0]
        eij = [0, 0, 0, 0]
        ei0j = [0, 0, 0, 0]

        for i in range(5):
            rnext = []
            for k in range(5):
                sum[0], sum[1], sum[2], sum[3] = 0, 0, 0, 0
                for j in range(5):
                    eij[0] = NormalizedMatrix[i][j][0][0]
                    eij[1] = NormalizedMatrix[i][j][0][1]
                    eij[2] = NormalizedMatrix[i][j][1][0]
                    eij[3] = NormalizedMatrix[i][j][1][1]

                    ei0j[0] = NormalizedMatrix[k][j][0][0]
                    ei0j[1] = NormalizedMatrix[k][j][0][1]
                    ei0j[2] = NormalizedMatrix[k][j][1][0]
                    ei0j[3] = NormalizedMatrix[k][j][1][1]
                    for k in range(4):
                        if eij[k] - ei0j[k] >= 0:
                            sum[k] += Weight[j]
                        else:
                            sum[k] += 0
                    # 获取个体
                sum_small = ([sum[0], sum[1]], [sum[2], sum[3]])
                rnext.append(sum_small)
            Gik.append(rnext)
        return Gik

    def DominantedMatrix(self, NormalizedMatrix, Weight):
        '''
        支配矩阵
        :param NormalizedMatrix: 区间值矩阵
        :param Weight: 权重
        :return:
        '''
        Dik = []
        eij = [0, 0, 0, 0]
        ei0j = [0, 0, 0, 0]

        for i in range(5):
            rnext = []
            for k in range(5):
                sum = 0
                down_max = 0
                for j in range(5):
                    eij[0] = NormalizedMatrix[i][j][0][0]
                    eij[1] = NormalizedMatrix[i][j][0][1]
                    eij[2] = NormalizedMatrix[i][j][1][0]
                    eij[3] = NormalizedMatrix[i][j][1][1]

                    ei0j[0] = NormalizedMatrix[k][j][0][0]
                    ei0j[1] = NormalizedMatrix[k][j][0][1]
                    ei0j[2] = NormalizedMatrix[k][j][1][0]
                    ei0j[3] = NormalizedMatrix[k][j][1][1]
                    right = math.fabs(eij[0] + eij[1] + eij[2] + eij[3] - ei0j[0] - ei0j[1] - ei0j[2] - ei0j[3])
                    if down_max <= right:
                        down_max = right
                        # 下面个体
                        down_small = self.subtraction(NormalizedMatrix[i][j], NormalizedMatrix[k][j], self.q)
                    for k in range(4):
                        if eij[k] - ei0j[k] <= 0:
                            if sum <= j:
                                sum = j
                    # 上面个体
                    up_small = self.subtraction(NormalizedMatrix[i][sum], NormalizedMatrix[k][sum], self.q)

                rnext.append(self.division(up_small, down_small, self.q))
            Dik.append(rnext)
        return Dik

    def ConcordanceMatrix(self,Matrix):
        '''
        协和矩阵
        :param Matrix: 区间值矩阵
        :param Weight: 权重
        :return:
        '''
        eij=[0, 0, 0, 0]
        avg=0
        m = 5
        for i in range(5):
            for j in range(5):
                eij[0] = Matrix[i][j][0][0]
                eij[1] = Matrix[i][j][0][1]
                eij[2] = Matrix[i][j][1][0]
                eij[3] = Matrix[i][j][1][1]
                avg+=eij[0]+eij[1]+eij[2]+eij[3]
        avg=avg/m/(m-1)/4

        sum = [0, 0, 0, 0]
        fik=[]
        for i in range(5):
            snext=[]
            for j in range(5):
                eij[0] = Matrix[i][j][0][0]
                eij[1] = Matrix[i][j][0][1]
                eij[2] = Matrix[i][j][1][0]
                eij[3] = Matrix[i][j][1][1]
                for k in range(4):
                    if eij[k]>=avg:
                        sum[k]=1
                    else:
                        sum[k]=0
                sum_small = ([sum[0], sum[1]], [sum[2], sum[3]])
                snext.append(sum_small)
            fik.append(snext)
        return fik

    def DiscordanceMatrix(self,Matrix):
        '''
        不协调矩阵
        :param Matrix: 区间值矩阵
        :param Weight: 权重
        :return:
        '''
        eij=[0, 0, 0, 0]
        avg=0
        m = 5
        for i in range(5):
            for j in range(5):
                eij[0] = Matrix[i][j][0][0]
                eij[1] = Matrix[i][j][0][1]
                eij[2] = Matrix[i][j][1][0]
                eij[3] = Matrix[i][j][1][1]
                avg+=eij[0]+eij[1]+eij[2]+eij[3]
        avg=avg/m/(m-1)/4

        sum = [0, 0, 0, 0]
        eik=[]
        for i in range(5):
            snext=[]
            for j in range(5):
                eij[0] = Matrix[i][j][0][0]
                eij[1] = Matrix[i][j][0][1]
                eij[2] = Matrix[i][j][1][0]
                eij[3] = Matrix[i][j][1][1]
                for k in range(4):
                    if eij[k]>=avg:
                        sum[k]=1
                    else:
                        sum[k]=0
                sum_small = ([sum[0], sum[1]], [sum[2], sum[3]])
                snext.append(sum_small)
            eik.append(snext)
        return eik

    def AggregateDominantMatrix(self,fMatrix,eMatrix):
        '''
        聚合占优矩阵
        :param fMatrix: 协调矩阵
        :param eMatrix: 不协调矩阵
        :return:
        '''
        P=[]
        for i in range(5):
            next=[]
            for j in range(5):
                pij=self.multiplication(fMatrix[i][j],eMatrix[i][j],self.q)
                next.append(pij)
            P.append(next)
        return P

    def getFinalUtilityScore(self,ScoreMatrix,Weight):
        '''
        获取最终效用得分
        :param ScoreMatrix: 得分矩阵
        :param Weight: 权重
        :return:
        '''
        U = []
        for Row in range(len(ScoreMatrix)):
            u0=0
            for Column in range(len(ScoreMatrix[0])):
                u0+=Weight[Column]*ScoreMatrix[Row][Column]
            U.append(u0)
        return U

    def getResult(self):
        '''
        最终结果
        :param Matrix:
        :param q:
        :return:
        '''
        Matrix = self.Normalized(self.matrix, self.weight)


        DMatrix=self.DominantMatrix(Matrix, self.weight)

        DdMatrix=self.DominantedMatrix(Matrix, self.weight)

        FMatrix=self.ConcordanceMatrix(DMatrix)
        EMatrix=self.DiscordanceMatrix(DdMatrix)
        PMatrix=self.AggregateDominantMatrix(FMatrix,EMatrix)

        Pnext=[]
        Weight=[]
        for i in range (5):
            x=[self.weight[i],self.weight[i]],[self.weight[i],self.weight[i]]
            Weight.append(x)

        for i in range (5):
            for j in range(5):
                if j==0:
                    sum1=self.multiplication(PMatrix[i][j],Weight[i],self.q)
                else:
                    sum1=self.addition(sum1,self.multiplication(PMatrix[i][j],Weight[i],self.q),self.q)

            Pnext.append(sum1)

        U=[]
        for i in range(5):
            U.append(self.getscore(Pnext[i]))
        U=[i/sum(U) for i in U]
        return U


if __name__ == "__main__":
    Matrix = np.array([[([0.58, 0.75], [0.1, 0.2]), ([0.7, 0.78], [0.2, 0.3]), ([0.5, 0.78], [0.1, 0.2]),
                        ([0.65, 0.7], [0.3, 0.35]), ([0.4, 0.5], [0.5, 0.6])],
                       [([0.5, 0.6], [0.1, 0.2]), ([0.75, 0.78], [0.2, 0.3]), ([0.6, 0.78], [0.1, 0.15]),
                        ([0.7, 0.8], [0.2, 0.3]), ([0.5, 0.6], [0.4, 0.5])],
                       [([0.5, 0.78], [0.1, 0.2]), ([0.6, 0.7], [0.3, 0.4]), ([0.7, 0.78], [0.2, 0.3]),
                        ([0.6, 0.7], [0.3, 0.4]),
                        ([0.35, 0.45], [0.5, 0.65])],
                       [([0.75, 0.780], [0.2, 0.3]), ([0.6, 0.75], [0.2, 0.3]), ([0.7, 0.78], [0.2, 0.3]),
                        ([0.55, 0.65], [0.3, 0.4]), ([0.35, 0.4], [0.6, 0.65])],
                       [([0.6, 0.75], [0.3, 0.4]), ([0.5, 0.6], [0.4, 0.5]), ([0.6, 0.7], [0.3, 0.4]),
                        ([0.5, 0.6], [0.4, 0.5]),
                        ([0.1, 0.2], [0.4, 0.5])]])
    #weight = (0.1, 0.15, 0.2, 0.25, 0.3)
    weight = (0.2, 0.2, 0.2, 0.2, 0.2)
    maut = ELECTRE(Matrix, weight, 1)
    result = maut.getResult()
    print(result)
